package tau.dimes.config.ipGeo;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.TreeMap;

import tau.dimes.config.ConfigurationException;
import tau.dimes.config.ConfigurationNode;
import tau.dimes.config.ConfigurationSource;
import tau.dimes.util.ReflectionHelper;

public class IpGeoConfiguration
{
	private static IpGeoConfiguration instance;

	private static String SECTION_NAME = "ipGeoConfiguration";
	private static String PROVIDERS_NODE_NAME = "providers";
	private static String PROVIDER_NODE_NAME = "provider";
	private static String DEFAULT_PROVIDER_ATTRIBUTE = "defaultProvider";

	private final Map<String, IpGeoProvider> providers;
	private String defaultProviderName;

	private IpGeoConfiguration(ConfigurationSource source) throws ConfigurationException
	{
		providers = new TreeMap<String, IpGeoProvider>();

		ConfigurationNode ipGeoNode = source.getConfigurationNode(SECTION_NAME);
		if (ipGeoNode == null)
			throw new ConfigurationException(SECTION_NAME + " is missing from configuration.");

		ConfigurationNode providersNode = ipGeoNode.getChild(PROVIDERS_NODE_NAME);
		try
		{
			if (providersNode != null)
			{
				for (ConfigurationNode providerNode : providersNode.getChildren(PROVIDER_NODE_NAME))
				{
					IpGeoProvider provider = new IpGeoProvider();
					ReflectionHelper.SetProperties(provider, providerNode.getAttributes());
					providers.put(provider.getName(), provider);
					if (defaultProviderName == null)
						defaultProviderName = provider.getName();
				}

				if (ipGeoNode.hasAttribute(DEFAULT_PROVIDER_ATTRIBUTE))
				{
					defaultProviderName = ipGeoNode.getAttribute(DEFAULT_PROVIDER_ATTRIBUTE);
					if (!providers.containsKey(defaultProviderName))
						throw new ConfigurationException("Default provider not found");
				}
			}
		}
		catch (NoSuchMethodException e)
		{
			throw new ConfigurationException(e);
		}
		catch (IllegalArgumentException e)
		{
			throw new ConfigurationException(e);
		}
		catch (IntrospectionException e)
		{
			throw new ConfigurationException(e);
		}
		catch (IllegalAccessException e)
		{
			throw new ConfigurationException(e);
		}
		catch (InvocationTargetException e)
		{
			throw new ConfigurationException(e);
		}
	}

	private static IpGeoConfiguration getInstance()
	{
		return instance;
	}

	public static void initInstance(ConfigurationSource source) throws ConfigurationException
	{
		instance = new IpGeoConfiguration(source);
	}
	
	public static String getDefaultProviderName()
	{
		return getInstance().defaultProviderName;
	}
	
	public static IpGeoProvider getProvider(String name)
	{
		return getInstance().providers.get(name);
	}
}
